﻿using System;
using System.Windows.Input;

namespace MvvmFx.Common.ViewModels.Commands
{
    /// <summary>
    /// A class that implements <see cref="ICommand"/> by deriving from <see cref="ViewModelCommand"/>,
    /// and adds the functionality to specify an <see cref="Action{T}"/> and a <see cref="Predicate{T}"/>
    /// to invoke for the Execute and CanExecute logic of the command.
    /// </summary>
    public class ActionCommand : ViewModelCommand
    {
        #region Fields

        readonly Action<object> execute;
        readonly Predicate<object> canExecute;

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="ActionCommand"/> class.
        /// </summary>
        /// <param name="execute">The execute.</param>
        public ActionCommand(Action<object> execute)
            : this(execute, null)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ActionCommand"/> class.
        /// </summary>
        /// <param name="execute">The action to invoken when the command is executed.</param>
        /// <param name="canExecute">The predicate to invoke when the CanExecute method is evaluated.</param>
        public ActionCommand(Action<object> execute, Predicate<object> canExecute)
        {
            if (execute == null)
                throw new ArgumentNullException("execute");

            this.execute = execute;
            this.canExecute = canExecute;
        }

        #endregion

        #region [ Protected Overrides ]

        /// <summary>
        /// Invokes the action
        /// </summary>
        /// <param name="parameter">The parameter required to execute a unit of logic.</param>
        protected sealed override void OnExecute(object parameter)
        {
            execute(parameter);
        }

        /// <summary>
        /// Invokes the predicate to check if the command can be executed
        /// </summary>
        /// <param name="parameter">The object to be passed to the command can execute function.</param>
        /// <returns>If the command can be executed.</returns>
        protected sealed override bool OnCanExecute(object parameter)
        {
            return canExecute == null ? true : canExecute(parameter);
        }

        #endregion
    }
}